using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public enum PlayerState      //枚举类存一下玩家的状态 如果之后需要添加新的状态需要在写在这里
{
    Idle, Walk, Jump, Fall, Land, Touch, React, Hit
}
public enum PlayerElement
{
    none, fire, water
}

public class ElementEffect
{
	public bool IsNone;
	public GameObject Effect;
	
	public void echo()
	{
		if (IsNone)
		{
			return;
		}
		else
		{
			
		}
	}
}

public class Player_FSM : MonoBehaviour
{
    [SerializeField] float runSpeed  = 3f;      //运动速度
    [SerializeField] float acceleration = 15f;  //加速度 从Idle状态到Walk状态在到达runSpeed之前会有一个加速过程 让人物运动更加自然
    [SerializeField] float deceleration = 10f;  //减速度 同理
    [SerializeField] float jumpForce = 5f;      //起跳力度 越大跳的越高
    [SerializeField] float jumpBufferTime = 0.5f;   //跳跃输入缓冲时间 可以提高跳跃键的"手感" 在按下跳跃键后的jumoBufferTime时间内 玩家只要处于可以跳起的状态 就会跳起来
    [SerializeField] public AnimationCurve dushSpeedCurveX;  //冲刺x轴速度曲线
    [SerializeField] public AnimationCurve dushSpeedCurveY;  //冲刺y轴速度曲线
    [SerializeField] public float FloatInLiquidY = 3f;       //在液体中上浮或下沉的力度

    IState currentState;
	public PlayerElement currentEle;
    Dictionary<PlayerState,IState> stateTable = new Dictionary<PlayerState,IState>();
	
    //public Dictionary<PlayerBuff, PlayerBuffInfo> buffTable = new Dictionary<PlayerBuff, PlayerBuffInfo>();

    Rigidbody2D rb2D;                               //获取刚体组件
    Animator animator;                              //获取动画组件
    PlayerInputActions inputActions;                //获取输入组件（关于这个组件的教程可以B站搜索"阿严Gaming" 强推！）
    GroundDector groundDector;                      //地面检测器 （玩家预制体的子物体 用于检测地面）
    public TouchDector touchDector;
    ReactDector reactDector;
    //Player_Canvas playerCanvas;                     //用于显示血条UI的 之后也可以在这里写一些别的玩家可调动资源

    public float MoveSpeed => rb2D.velocity.x;      //可获取/修改的玩家当前移动速度绝对值
    public float Direction => transform.localScale.x;   //可获取/修改的玩家当前方向
    public Vector2 Move => inputActions.GamePlay.Move.ReadValue<Vector2>(); //输入组件用变量
    public float MoveX => Move.x;           //x方向速度值
    public float MoveY => Move.y;           //y方向速度值
    public bool IsMove => MoveX == 0 ? false : true;       //判断玩家x方向速度值是否为0
    public bool IsMoveY => MoveY == 0 ? false : true;      //判断玩家y方向速度值是否为0
    public bool IsJump => inputActions.GamePlay.Jump.WasPressedThisFrame();  //玩家这一帧是否按下了跳跃键
    public bool IsFall => rb2D.velocity.y <= 0;  //是否正在下落（用于从Jump状态转到Fall状态）
    public bool IsGround => groundDector.IsGrounded; //判断是否在地面上（用于从Fall状态转到Land状态）

    public bool IsTouch { get; set; }
	public bool PreIsTouch { get; set; }

    public bool IsReact => reactDector.IsReact;
    public bool IsHit { get; set; }
    //public bool IsLiquid => liquidDector.IsLiquid;
    public bool HasJumpBuffer { get; set; }     //是否处于跳跃缓冲中
    public float spray_stage_1_thrs = 0.2f;
    public float spray_stage_2_thrs = 3.6f;
	public GameObject Effects;

    WaitForSeconds waitForJumpBuffer;   //协程用变量
    WaitForSeconds waitForShadowGet;    //协程用变量 
    private void Awake()        //这里把一些变量和组件进行一个初始化
    {
        rb2D = GetComponent<Rigidbody2D>();
        animator = GetComponent<Animator>();
        groundDector = GetComponentInChildren<GroundDector>();
        touchDector = GetComponentInChildren<TouchDector>();
        reactDector = GetComponentInChildren<ReactDector>();
        inputActions = new PlayerInputActions();
        waitForJumpBuffer = new WaitForSeconds(jumpBufferTime);
    }
    private void Start()
    {
        stateTable.Add(PlayerState.Idle, new PlayerState_Idle(this, animator));         //这里把所有的状态都注册好
        stateTable.Add(PlayerState.Walk, new PlayerState_Walk(this, animator));
        stateTable.Add(PlayerState.Jump, new PlayerState_Jump(this, animator));
        stateTable.Add(PlayerState.Fall, new PlayerState_Fall(this, animator));
        stateTable.Add(PlayerState.Land, new PlayerState_Land(this, animator));
        stateTable.Add(PlayerState.Hit, new PlayerState_Hit(this, animator));
        stateTable.Add(PlayerState.Touch, new PlayerState_Touch(this, animator));
        stateTable.Add(PlayerState.React, new PlayerState_React(this, animator));
        StateOn(PlayerState.Fall);
    }
    private void OnEnable()
    {
        EnableInputAction();                //启用输入
		PreIsTouch = false;
		IsTouch = false;
    }
    private void Update()
	{
		currentState.LogicUpdate();         //状态机逻辑更新 涉及判断等逻辑问题的最好都写在这里
	}
	private void FixedUpdate()
    {
        currentState.PhysicsUpdate();       //状态机物理更新 涉及速度的最好都写在这里
    }
    public void StateOn(PlayerState state)  //启动某个状态 没事少用 一般用下面那个
    {
        currentState = stateTable[state];
        currentState.Enter();
    }
    public void StateSwitch(PlayerState state)    //切换到某个状态
    {
        currentState.Exit();
        StateOn(state);
    }
    public void EnableInputAction()              //启用输入检测的函数
    {
        inputActions.GamePlay.Enable();
        Cursor.lockState = CursorLockMode.Locked; //锁定并隐藏鼠标 如果不需要可以注释掉
    }
    public void DisableInputAction()            //关闭输入检测的函数 或许过场动画等不希望玩家能操控角色的时候会用得上
    {
        inputActions.GamePlay.Disable();
        Cursor.lockState = CursorLockMode.Confined;
    }
    public void Flip()      //转身函数
    {
        if (IsMove)     //如果玩家移动了 就根据玩家速度的方向进行一个转身（通过改变localScale.x的值来实现）
        {
            transform.localScale = new Vector3(MoveX, transform.localScale.y, transform.localScale.z);
        }
    }
    public void FlipInAir() //空中的转身函数
    {   
        if (IsMove)     //区别在于在空中时速度突然变化会很不自然 采用了更自然的变化
        {
            transform.localScale = new Vector3(MoveX, 1, 1);
        }
        SetVelocityX(Mathf.MoveTowards(rb2D.velocity.x, runSpeed * MoveX, acceleration * Time.deltaTime));
    }
    public void SetVelocityX(float speed)   //设置X方向速度
    {
        rb2D.velocity = new Vector2(speed, rb2D.velocity.y);
    }
    public void SetVelocityY(float speed)
    {
        rb2D.velocity = new Vector2(rb2D.velocity.x,speed);
    }

    public void SetVelocity(Vector2 speed) //X、Y方向速度一起设置
    {
        rb2D.velocity = speed;
    }

    public void SetJumpBuffer()//设置跳跃缓冲 会在下落时按下了跳跃键时调用 落地后如果在缓冲时间内会直接跳起来 来提升操作的宽容度
    {
        StopCoroutine(nameof(JumpBufferCoroutine));
        StartCoroutine(nameof(JumpBufferCoroutine));
    }
    public float GetRunSpeed()  //获取最大跑步速度
    {
        return runSpeed;
    }
    public void SetRunSpeed(float speed)
    {
        runSpeed = speed;
    }
    public float GetAcceleration()
    {
        return acceleration;
    }
    public void SetAcceleration(float new_acceleration)
    {
        acceleration = new_acceleration;
    }
    public float GetDeceleration()
    {
        return deceleration;
    }
    public float GetJumpForce()     //获取跳跃力度
    {
        return jumpForce;
    }
    public float GetDirection()     //获取当前方向
    {
        return transform.localScale.x;
    }
    IEnumerator JumpBufferCoroutine()       //进行跳跃缓冲的协程
    {
        HasJumpBuffer = true;
        yield return waitForJumpBuffer;
        HasJumpBuffer = false;
    }
	public void SwitchElement(PlayerElement ele)
	{
		currentEle = ele;
		int mode = (int)(currentEle);
		for (int i = 0; i < Effects.transform.childCount; i++)
        {
            Effects.transform.GetChild(i).gameObject.SetActive(false);
        }
		if(mode > 0)
		{
     	   Effects.transform.GetChild(mode - 1).gameObject.SetActive(true);
		}
	}
}
